package com.kesh.ltank.screens;

import java.util.List;

import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;

import com.android.framework.Game;
import com.android.framework.Graphics;
import com.android.framework.Input.TouchEvent;
import com.android.framework.Screen;
import com.kesh.ltank.elements.LTank;
import com.kesh.ltank.elements.Level;
import com.kesh.ltank.elements.Platform;
import com.kesh.ltank.game.GlobalVars;
import com.kesh.ltank.game.GlobalVars.Direction;
import com.kesh.ltank.game.GlobalVars.GameImages;
import com.kesh.ltank.game.GlobalVars.GameSounds;
import com.kesh.ltank.game.GlobalVars.GameState;
import com.kesh.ltank.game.GlobalVars.ScreenImages;
import com.kesh.ltank.game.Utils;

public class GameScreen extends Screen {

	GameState gameState = GameState.Ready;
	private Level lvl;
	private Platform pltfrm;
	private LTank ltank;
	
	private LTank undoList[];
	private int undoCnt;
	
	private Paint paint1, paint3, paint2, paint4, paint5;
	private boolean fireButtonPressed;
	private boolean undoButtonPressed;
	private boolean redoButtonPressed;
	
	private boolean isDragged;
	private int dragCount;
	private Point dragStart;
	private Point dragEnd;
	private Direction dragDirection;

	public GameScreen(Game game) {
		super(game);

		paint1 = new Paint();
		paint1.setTextSize(30);
		paint1.setTextAlign(Paint.Align.CENTER);
		paint1.setAntiAlias(true);
		paint1.setColor(Color.BLACK);

		paint2 = new Paint();
		paint2.setTextSize(50);
		paint2.setTextAlign(Paint.Align.CENTER);
		paint2.setAntiAlias(true);
		paint2.setColor(Color.BLACK);
		
		paint3 = new Paint();
		paint3.setTextSize(70);
		paint3.setTextAlign(Paint.Align.CENTER);
		paint3.setAntiAlias(true);
		paint3.setColor(Color.WHITE);

		paint4 = new Paint();
		paint4.setTextSize(80);
		paint4.setTextAlign(Paint.Align.CENTER);
		paint4.setAntiAlias(true);
		paint4.setColor(Color.WHITE);

		paint5 = new Paint();
		paint5.setTextSize(40);
		paint5.setTextAlign(Paint.Align.CENTER);
		paint5.setAntiAlias(true);
		paint5.setColor(Color.WHITE);

		lvl = new Level();
		lvl.loadLevel(GlobalVars.currentLevel);
		
		ltank = new LTank(lvl);
		pltfrm = new Platform();
		
		undoCnt = 0;
		undoList = new LTank[undoCnt+1];
		undoList[undoCnt]=ltank.clone();

		fireButtonPressed=false;
		undoButtonPressed=false;
		redoButtonPressed=false;
		isDragged = false;
		dragStart = new Point(0,0);
		dragEnd = new Point(0,0);
		dragDirection = null;
		dragCount=0;
	}

	@Override
	public void update(float deltaTime) {
		List<TouchEvent> touchEvents = game.getInput().getTouchEvents();

		switch (gameState) {
			case Ready:
				updateReady(touchEvents);
				break;
			case Running:
				updateRunning(touchEvents, deltaTime);
				break;
			case Paused:
				updatePaused(touchEvents);
				break;
			case Drowned:
				updateGameOver(touchEvents);
				break;
			case Dead:
				updateGameOver(touchEvents);
				break;
			case Won:
				updateWon(touchEvents);
				break;
		}
	}

	private void updateReady(List<TouchEvent> touchEvents) {
		if (touchEvents.size() > 0)
			gameState = GameState.Running;
	}

	private void updateRunning(List<TouchEvent> touchEvents, float deltaTime){
		
		int stateChangeCount = ltank.getStateChangeCount();
		
		switch(ltank.getCurTankState()){
			case PrevATankFired:
				ltank.fireATankPrev();
				break;
			case CurATankFired:
				ltank.fireATankCur();
				break;
			case BothATankFired:
				ltank.fireBothATanks();
				break;
			case OnStream:
				undoButtonPressed=false;
				redoButtonPressed=false;
				int len = touchEvents.size();
				for (int i = 0; i < len; i++) {
					TouchEvent event = touchEvents.get(i);
					if (event.type == TouchEvent.TOUCH_DOWN) {
						if (Utils.inBounds(event, 320, 685, 125, 60)) {
							undo();
							undoButtonPressed = true;
						} else if (Utils.inBounds(event, 35, 685, 125, 60)) {
							redo();
							redoButtonPressed = false;
						}
					}
				}
				ltank.moveTank(ltank.getCurTankDirection());
				break;
			case OnIce:
				ltank.moveTank(ltank.getCurTankDirection());
				break;
			case OnTunnel:
				ltank.moveTank(ltank.getCurTankDirection());
				break;
			case OnWater:
				gameState=GameState.Drowned;
				break;
			case ShotDead:
				gameState=GameState.Dead;
				break;
			case ReachedFlag:
				gameState=GameState.Won;
				break;
			case Firing:
				ltank.fireTank();
				break;
			case Moving:case Blocked:
				len = touchEvents.size();
				if (len <= 0) {
					if (isDragged & dragCount>10) {
						if (dragDirection != null)
							if (ltank.moveTank(dragDirection))
								ltank.incrementTankMoves();
					}
				} else {
					for (int i = 0; i < len; i++) {
						TouchEvent event = touchEvents.get(i);
						if (event.type == TouchEvent.TOUCH_DOWN) {
							if (Utils.inBounds(event, 320, 685, 125, 60)) {
								undoButtonPressed = true;
							} else if (Utils.inBounds(event, 35, 685, 125, 60)) {
								redoButtonPressed = true;
							} else if (Utils.inBounds(event, 195, 680, 90, 90)) {
								fireButtonPressed = true;
							}
						} else if (event.type == TouchEvent.TOUCH_DRAGGED) {
							if (!isDragged && !undoButtonPressed && !redoButtonPressed && !fireButtonPressed) {
								isDragged = true;
								dragStart = new Point(event.x, event.y);
							} 
							if(isDragged){
								dragCount++;
								dragEnd = new Point(event.x, event.y);
								Direction tmpDirection = getDirection(dragStart, dragEnd);
								if(tmpDirection != dragDirection) dragCount=0;
								dragDirection=tmpDirection;
								if(dragCount>10)
									if (dragDirection != null)
										if (ltank.moveTank(dragDirection))
											ltank.incrementTankMoves();
							}
						} else if (event.type == TouchEvent.TOUCH_UP) {
							if(isDragged){
								dragCount=0;
								isDragged = false;
								dragEnd = new Point(event.x, event.y);
								dragDirection = getDirection(dragStart, dragEnd);
								if (dragDirection != null)
									if (ltank.moveTank(dragDirection))
										ltank.incrementTankMoves();
							} else {
								if (undoButtonPressed) {
									undo();
									undoButtonPressed = false;
								} else if (redoButtonPressed) {
									redo();
									redoButtonPressed = false;
								} else if (fireButtonPressed) {
									fireButtonPressed = false;
									ltank.fireTank();
									GameSounds.ShootSound.play();
									ltank.incrementTankShots();
								}
							}
						}
					}
				}
				break;
		}
		
		if(ltank.getStateChangeCount()>stateChangeCount){
			undoCnt++;
			undoList = (LTank[])Utils.resizeArray(undoList, undoCnt+1);
			undoList[undoCnt]=ltank.clone();
		}
	}

	private Direction getDirection(Point p1, Point p2){
		
		Direction tmpDirection = null;
		int xDiff = p1.x - p2.x;
		int yDiff = p1.y - p2.y;
		
		if(Math.abs(xDiff)>=Math.abs(yDiff)){
			if (xDiff < 0){
				tmpDirection= Direction.Right;
			} else if (xDiff > 0) {
				tmpDirection= Direction.Left;
			}
		} else {
			if (yDiff < 0){
				tmpDirection= Direction.Down;
			} else if (yDiff > 0) {
				tmpDirection= Direction.Up;
			}
		}
		return tmpDirection;
	}
	
	private void updatePaused(List<TouchEvent> touchEvents) {
		int len = touchEvents.size();
		for (int i = 0; i < len; i++) {
			TouchEvent event = touchEvents.get(i);
			if (event.type == TouchEvent.TOUCH_DOWN) {
				if (Utils.inBounds(event, 120, 380, 240, 40)) {
					resume();
				}
				if (Utils.inBounds(event, 140, 480, 205, 40)) {
					restart();
				}
				if (Utils.inBounds(event, 150, 580, 175, 40)) {
					nullify();
					goToMenu();
				}
			}
		}
	}

	private void updateGameOver(List<TouchEvent> touchEvents) {
		int len = touchEvents.size();
		for (int i = 0; i < len; i++) {
			TouchEvent event = touchEvents.get(i);
			if (event.type == TouchEvent.TOUCH_DOWN) {
				if (Utils.inBounds(event, 120, 380, 240, 40)) {
					gameState = GameState.Running;
					undo();
				}
				if (Utils.inBounds(event, 140, 480, 205, 40)) {
					restart();
				}
				if (Utils.inBounds(event, 150, 580, 175, 40)) {
					nullify();
					goToMenu();
				}
			}
		}
	}

	private void updateWon(List<TouchEvent> touchEvents) {
		int len = touchEvents.size();
		for (int i = 0; i < len; i++) {
			TouchEvent event = touchEvents.get(i);
			if (event.type == TouchEvent.TOUCH_DOWN) {
				if (Utils.inBounds(event, 90, 480, 300, 40)) {
					nextLevel();
				}
				if (Utils.inBounds(event, 150, 580, 175, 40)) {
					nullify();
					goToMenu();
				}
			}
		}
	}

	@Override
	public void paint(float deltaTime) {
		Graphics g = game.getGraphics();
		
		g.clearScreen(Color.BLACK);
		
		g.drawImage(ScreenImages.Bacground.image, 0, 0);
	
		pltfrm.paintPlatform(g, ltank);
		
		g.drawRectWithBorder(ltank.getCurTankBullet().getCurBulletRect(), Color.GREEN);
		
		g.drawRectWithBorder(ltank.getaTankPrev().getTankBullet().getCurBulletRect(), Color.RED);
		g.drawRectWithBorder(ltank.getaTankCur().getTankBullet().getCurBulletRect(), Color.RED);
		
		g.drawString(Integer.toString(ltank.getTankMoves()), 75, 155, paint1);
		g.drawString(Integer.toString(GlobalVars.currentLevel), 240, 153, paint2);
		g.drawString(Integer.toString(ltank.getTankShots()), 415, 155, paint1);
		
		
		switch (gameState) {
			case Ready:
				drawReadyUI();
				break;
			case Running:
				drawRunningUI();
				break;
			case Paused:
				drawPausedUI();
				break;
			case Drowned:
				drawDrownedUI();
				break;
			case Dead:
				drawDeadUI();
				break;
			case Won:
				drawWonUI();
				break;
		}
	}


	private void nullify() {
		paint1 = null;
		paint3 = null;
		paint2 = null;
		lvl = null;
		pltfrm = null;
		ltank = null;
		System.gc();
	}

	private void drawReadyUI() {
		Graphics g = game.getGraphics();
		g.drawARGB(155, 0, 0, 0);
		g.drawString("Tap to Start.", 240, 400, paint5);
	}

	private void drawRunningUI() {
		Graphics g = game.getGraphics();
		if(undoCnt<undoList.length-1){
			if(redoButtonPressed)
				g.drawImage(GameImages.ReDo_Pressed.image, 35, 685);
			else
				g.drawImage(GameImages.ReDo.image, 35, 685);
		}
		
		if(undoCnt>0){
			if(undoButtonPressed)
				g.drawImage(GameImages.UnDo_Pressed.image, 320, 685);
			else
				g.drawImage(GameImages.UnDo.image, 320, 685);
		}	
		
		if(fireButtonPressed)
			g.drawImage(GameImages.FireButton_Pressed.image, 195, 670);
		else 
			g.drawImage(GameImages.FireButton.image, 195, 670);
	}

	private void drawPausedUI() {
		Graphics g = game.getGraphics();
		g.drawARGB(155, 0, 0, 0);
		g.drawString("Game", 240, 220, paint4);
		g.drawString("Paused", 240, 280, paint4);
		g.drawString("Resume", 240, 420, paint3);
		g.drawString("Restart", 240, 520, paint3);
		g.drawString("Menu", 240, 620, paint3);
	}

	private void drawDeadUI() {
		Graphics g = game.getGraphics();
		g.drawARGB(155, 0, 0, 0);
		g.drawString("You are", 240, 220, paint4);
		g.drawString("Shot Dead", 240, 280, paint4);
		g.drawString("Undo", 240, 420, paint3);
		g.drawString("Restart", 240, 520, paint3);
		g.drawString("Menu", 240, 620, paint3);
	}

	private void drawDrownedUI() {
		Graphics g = game.getGraphics();
		g.drawARGB(155, 0, 0, 0);
		g.drawString("You", 240, 220, paint4);
		g.drawString("Drowned", 240, 280, paint4);
		g.drawString("Undo", 240, 420, paint3);
		g.drawString("Restart", 240, 520, paint3);
		g.drawString("Menu", 240, 620, paint3);
	}

	private void drawWonUI() {
		Graphics g = game.getGraphics();
		g.drawARGB(155, 0, 0, 0);
		g.drawString("You Won !", 240, 220, paint4);
		g.drawString("Next Level", 240, 520, paint3);
		g.drawString("Menu", 240, 620, paint3);
	}
	
	@Override
	public void pause() {
		if (gameState == GameState.Running)
			gameState = GameState.Paused;
	}

	@Override
	public void resume() {
		if (gameState == GameState.Paused)
			gameState = GameState.Running;
	}

	@Override
	public void dispose() {
		
	}

	@Override
	public void backButton() {
		pause();
	}

	public void undo(){
		if(undoCnt>0){
			isDragged=false;
			dragCount=0;
			undoCnt--;
			ltank=null;
			ltank = undoList[undoCnt].clone();
		}
	}
	
	public void redo(){
		if(undoCnt<undoList.length-1){
			undoCnt++;
			ltank = undoList[undoCnt].clone();
		}
	}
	
	public void nextLevel() {
		Utils.saveLevelNumber(game.getFileIO(),GlobalVars.currentLevel);
		GlobalVars.currentLevel = GlobalVars.currentLevel+1;
		nullify();
		game.setScreen(new GameScreen(game));
	}

	public void restart() {
		nullify();
		game.setScreen(new GameScreen(game));
	}

	private void goToMenu() {
		game.setScreen(new MainMenuScreen(game));
	}

}